﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Web;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using TanashCMS.Business.Utilities;

namespace TanashCMS.Business.Task
{
    public class TemplateTask
    {
        private string _contentId=string.Empty, _templatePath;
        private Uri _currentUrl;
        private TanashWebsite _website;
        private CMSObjectType _contentType;

        public TemplateTask(string contentId, string templatePath, Uri currentUrl, TanashWebsite website, CMSObjectType contentType)
        {
            _contentId = contentId;
            _templatePath = templatePath;
            _website = website;
            _contentType = contentType;
            _currentUrl = currentUrl;
        }
        public TemplateTask(Uri currentUrl, string templatePath, TanashWebsite website)
        {
            _templatePath = templatePath;
            _website = website;
            _currentUrl = currentUrl;
        }

        public void Process(Stream outputStream, System.Collections.Specialized.NameValueCollection parameters, XPathNavigator xmlNavigator)
        {
            XPathNavigator contentNode=null;
            if (_contentId.Equals(string.Empty))
            {
                GetContentForUrl(_currentUrl, xmlNavigator, out _contentId, out _contentType, out contentNode);
            }
            else
                contentNode = xmlNavigator.SelectSingleNode("//webpage[@id='" + _contentId + "']");

            // generate content for category or product
            string xhtmlContent = "", contentTransform="";
            if (_contentType == CMSObjectType.Category)
                contentTransform = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, @"xsl\category.xsl");
            else if (_contentType == CMSObjectType.Product)
                contentTransform = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, @"xsl\product.xsl");
            else if (Path.GetFileName(HttpContext.Current.Request.PhysicalPath) == "contact.aspx")
                contentTransform = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, @"xsl\contact.xsl");

            if (!string.IsNullOrEmpty(contentTransform))
                xhtmlContent = GeneratePageXHTMLContent(contentTransform, _currentUrl, _contentId, xmlNavigator);

            // generate the page template
            XsltArgumentList xArguments = new XsltArgumentList();
            xArguments.AddParam("id", "", _contentId);

            StringBuilder sbTemplate = new StringBuilder();
            StringWriter swTemplate = new StringWriter(sbTemplate);
            string templateTransform = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, @"\xsl\webpage-standard.xsl");

            HttpContext.Current.Trace.Write("templatePath1=" + _templatePath);
            Logger.Debug("templatePath1=" + _templatePath);
            if (_templatePath != "")
            {
                templateTransform = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, _templatePath.Replace("/", "\\").Trim('\\')); // determined in CMSPageBase OnPreInit
            }
            else
                templateTransform = Path.Combine(System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, _website.DefaultTemplate.Replace("/", "\\").Trim('\\'));

            xArguments.AddParam("currentUrl", "", _currentUrl.ToString());
            if (xhtmlContent.Length > 0)
                xArguments.AddParam("xhtmlContent", "", xhtmlContent);
            else
                xArguments.AddParam("xhtmlContent", "", "-");

            if (contentNode != null)
            {
                if (contentNode.GetAttribute("homepage", "") == "1")
                    xArguments.AddParam("showIndex", "", _website.getOptionValue("ShowIndexOnHomePage"));
                else
                    xArguments.AddParam("showIndex", "", _website.getOptionValue("ShowIndexOnWebPages"));
            }

            if (_website.getOptionValue("IsBlogSite") != null && _website.getOptionValue("IsBlogSite") == "1")
            {
                if (parameters["from"] != null)
                    xArguments.AddParam("from", "", parameters["from"]);
            }

            XsltSettings settings = new XsltSettings(false, true);

            //context.Response.Write("website is " + website.Title + "<br/>");
            string xmlUri = new SitePublishTask(_website).getWebsiteXml(_website.ID);
            XslCompiledTransform xPageTransform = new XslCompiledTransform();

            // make sure we're targeting the template.xsl file
            if (Path.GetFileName(templateTransform) != "template.xsl")
                templateTransform = Path.Combine(templateTransform, "template.xsl");

            try
            {
                FileStream fs = new FileStream(templateTransform, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                StringBuilder sb = new StringBuilder();
                StreamReader r = new StreamReader(fs);
                sb.Append(r.ReadToEnd());

                StringReader reader = new StringReader(sb.ToString());
                XmlReader xslReader = XmlReader.Create(reader);
                xPageTransform.Load(xslReader, settings, new XmlUrlResolver());

                fs.Close();
                xslReader.Close();
            } catch (Exception e)
            {
                Logger.Fatal("Could not load template " + templateTransform, e);
                return;
            }

            xPageTransform.Transform(xmlNavigator, xArguments, swTemplate);
            swTemplate.Close();

            string xhtml = System.Web.HttpUtility.HtmlDecode(System.Web.HttpUtility.HtmlDecode(swTemplate.ToString()));
            xhtml = ReplacePaths(xhtml);

            StreamWriter writer = new StreamWriter(outputStream);
            writer.Write(xhtml);
            writer.Dispose();
        }

        public void GetContentForUrl(Uri url, XPathNavigator xmlNavigator, out string _contentId, out CMSObjectType _contentType, out XPathNavigator contentNode)
        {
            contentNode = null;
            _contentId = "";
            _contentType = CMSObjectType.WebPage;

            // webpage
            contentNode = xmlNavigator.SelectSingleNode(ContentXPathFromUrl(url, "webpage"));

            // category
            if (contentNode == null || !contentNode.IsNode)
            {
                contentNode = xmlNavigator.SelectSingleNode(ContentXPathFromUrl(url, "category"));
                _contentType = CMSObjectType.Category;
            }

            // product
            if (contentNode == null || !contentNode.IsNode)
            {
                contentNode = xmlNavigator.SelectSingleNode(ContentXPathFromUrl(url, "product"));
                _contentType = CMSObjectType.Product;
            }

            // homepage
            if (contentNode == null || !contentNode.IsNode)
            {
                contentNode = xmlNavigator.SelectSingleNode("/website/webpage[@homepage='1']");
                _contentType = CMSObjectType.WebPage;
            }

            if (contentNode == null || !contentNode.IsNode) return;

            /*
            _contentGuid = contentNode.GetAttribute("guid", "");
            string PageTypeID = _contentGuid.Substring(0, 2);
            if (Enum.IsDefined(typeof(CMSObjectType), int.Parse(PageTypeID)))
                _contentType = (CMSObjectType)Enum.Parse(typeof(CMSObjectType), int.Parse(PageTypeID).ToString());
            else // if no type specified assume it's a web page
                _contentType = CMSObjectType.WebPage;
             */
        }

        public string ContentXPathFromUrl(Uri url, string elementName)
        {
            // we make three attempts to find the matching content - page, category and product
            string[] parts = url.AbsolutePath.Substring(url.AbsolutePath.IndexOf("://") + 2).Split('/');

            string xpath = "/website";
            foreach (string part in parts)
                xpath += string.Format("/{0}[@key='{1}']", elementName, Path.GetFileNameWithoutExtension(part));

            return xpath;
        }

        public string GeneratePageXHTMLContent(string transformPath, Uri rootUrl, string contentid, XPathNavigator navigator)
        {
            // generate the page content
            string xhtmlContent = "";
            XsltSettings settings = new XsltSettings(false, true);
            XsltArgumentList xContentArguments = new XsltArgumentList();
            StringBuilder sbContent = new StringBuilder();
            StringWriter swContent = new StringWriter(sbContent);

            string xmlUri = new SitePublishTask(_website).getWebsiteXml(_website.ID);
            XslCompiledTransform xPageTransform = new XslCompiledTransform();

            xContentArguments.AddParam("rootUrl", "", rootUrl.ToString());
            xContentArguments.AddParam("id", "", contentid);
            xContentArguments.AddParam("categoryXPath", "", "//category[@id=537]");
            if (_website.SubFolderName == "collisstudios") // TODO: fix this awful hack
            {
                xContentArguments.AddParam("desiredThumbnailWidth", "", 150);
                xContentArguments.AddParam("desiredThumbnailHeight", "", 150);
            }

            xPageTransform.Load(transformPath, settings, new XmlUrlResolver());

            xPageTransform.Transform(navigator, xContentArguments, swContent);
            swContent.Close();

            // todo: need to html decode this result, twice.
            // i.e: Server.HtmlDecode(Server.HtmlDecode(swContent.ToString()));
            xhtmlContent = System.Web.HttpUtility.HtmlDecode(System.Web.HttpUtility.HtmlDecode(swContent.ToString()));
            xhtmlContent = ReplacePaths(xhtmlContent);

            return xhtmlContent;
        }

        public string ReplacePaths(string xhtml)
        {
            xhtml = xhtml.Replace("@templatepath@", _templatePath);

            return xhtml;
        }
    }
}
